import torch
import torch.nn as nn
import torch.nn.functional as F

class SEBlockLite(nn.Module):
    def __init__(self, in_channels, reduction=8):
        super(SEBlockLite, self).__init__()
        self.global_avg_pool = nn.AdaptiveAvgPool2d(1)
        self.fc1 = nn.Conv2d(in_channels, in_channels // reduction, kernel_size=1)
        self.fc2 = nn.Conv2d(in_channels // reduction, in_channels, kernel_size=1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        #return x
        squeezed = self.global_avg_pool(x)
        squeezed = self.fc1(squeezed)
        squeezed = F.relu(squeezed)
        excitation = self.fc2(squeezed)
        excitation = self.sigmoid(excitation)
        return x * excitation

class ConvNetWithSELiteOptimized(nn.Module):
    def __init__(self, num_classes=10):
        super(ConvNetWithSELiteOptimized, self).__init__()
        
        # 卷积层1 + Lite SE模块
        self.conv1 = nn.Conv2d(3, 64, kernel_size=3, padding=1)
        self.se1 = SEBlockLite(64, reduction=8)  # 更轻量的SE模块
        self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)

        # 卷积层2 + Lite SE模块
        self.conv2 = nn.Conv2d(64, 128, kernel_size=3, padding=1)
        self.se2 = SEBlockLite(128, reduction=8)  # 更轻量的SE模块
        self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)

        # 卷积层3 + Lite SE模块
        self.conv3 = nn.Conv2d(128, 256, kernel_size=3, padding=1)
        self.se3 = SEBlockLite(256, reduction=8)  # 更轻量的SE模块
        self.pool3 = nn.MaxPool2d(kernel_size=2, stride=2)

        # 卷积层4 + Lite SE模块
        self.conv4 = nn.Conv2d(256, 512, kernel_size=3, padding=1)
        self.se4 = SEBlockLite(512, reduction=8)  # 更轻量的SE模块
        self.pool4 = nn.MaxPool2d(kernel_size=2, stride=2)

        # 全连接层
        self.fc1 = nn.Linear(512 * 16 * 16, 1024)
        self.fc2 = nn.Linear(1024, num_classes)

    def forward(self, x):
        x = self.pool1(F.relu(self.conv1(x)))
        x = self.se1(x)

        x = self.pool2(F.relu(self.conv2(x)))
        x = self.se2(x)

        x = self.pool3(F.relu(self.conv3(x)))
        x = self.se3(x)

        x = self.pool4(F.relu(self.conv4(x)))
        x = self.se4(x)

        x = x.view(x.size(0), -1)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)

        return x
